package com.offcn.search.service.impl;

import com.alibaba.fastjson.JSON;
import com.offcn.entity.Result;
import com.offcn.search.dao.SearchMapper;
import com.offcn.search.service.SearchService;
import com.offcn.sellergoods.feign.ItemFeign;
import com.offcn.sellergoods.pojo.Item;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.*;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.*;

@Service
public class SearchServiceImpl implements SearchService {
    @Autowired
    private ItemFeign itemFeign;
    @Autowired
    private SearchMapper searchMapper;
    @Autowired
    private ElasticsearchRestTemplate elasticsearchRestTemplate;

    /**
     * 导入数据到es
     */
    @Override
    public void importEs() {
        // 调用服务获取数据
        Result<List<Item>> result = itemFeign.findByStatus("1");
        List<Item> itemList = result.getData();
        List<com.offcn.search.pojo.Item> items = JSON.parseArray(JSON.toJSONString(itemList), com.offcn.search.pojo.Item.class);
        for (com.offcn.search.pojo.Item item : items) {
            Map<String ,Object> specMap = JSON.parseObject(item.getSpec());
            item.setSpecMap(specMap);
        }
        // 保存数据到es
        searchMapper.saveAll(items);
    }


    /**
     * 关键字搜索
     */
    @Override
    public Map search(Map<String, String> searchMap) {
        // 1. 获取搜索关键字
        String keywords = searchMap.get("keywords");
        if (StringUtils.isEmpty(keywords)){
            keywords = "华为";
        }
        // 创建查询对象的构建器
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
        // 设置分组条件
        nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("CategoryGroup").field("category"));
        nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("BrandGroup").field("brand"));
        nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("SpecGroup").field("spec.keyword").size(100));
        // 设置查询的条件
        nativeSearchQueryBuilder.withQuery(QueryBuilders.matchQuery("title",keywords));
        // 过滤查询 多条件
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        if (!StringUtils.isEmpty(searchMap.get("brand"))){
            boolQuery.filter(QueryBuilders.matchQuery("brand",searchMap.get("brand")));
        }
        if (!StringUtils.isEmpty(searchMap.get("category"))){
            boolQuery.filter(QueryBuilders.matchQuery("category",searchMap.get("category")));
        }
        if (searchMap != null){
            for (String key : searchMap.keySet()) {
                // spec_网络
                if (key.startsWith("spec_")){
                    boolQuery.filter(QueryBuilders.termQuery("specMap."+key.substring(5)+".keyword",searchMap.get(key)));
                }
            }
        }
        // 500-1000  gt gte  lte  lt
        String price = searchMap.get("price");
        if (!StringUtils.isEmpty(price)){
            String[] split = price.split("-");
            if (!split[1].equalsIgnoreCase("*")){
                boolQuery.filter(QueryBuilders.rangeQuery("price").from(split[0],true).to(split[1],true));
            } else {
                boolQuery.filter(QueryBuilders.rangeQuery("price").gte(split[0]));
            }
        }
        nativeSearchQueryBuilder.withFilter(boolQuery);
        // 搜索分页
        int pageNum = 0 ;int pageSize = 0;
        String pageNumStr = searchMap.get("pageNum");
        if (!StringUtils.isEmpty(pageNumStr)){
            pageNum = Integer.parseInt(pageNumStr);
        }else {
            pageNum = 1;
        }
        String pageSizeStr = searchMap.get("pageSize");
        if (!StringUtils.isEmpty(pageSizeStr)){
            pageSize = Integer.parseInt(pageSizeStr);
        } else {
            pageSize = 10;
        }
        nativeSearchQueryBuilder.withPageable(PageRequest.of(pageNum -1 ,pageSize));
        // 排序  排序的字段  排序规则
        String sortField = searchMap.get("sortField");
        String sortRule = searchMap.get("sortRule");
        if (!StringUtils.isEmpty(sortRule) && !StringUtils.isEmpty(sortField)){
            nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort(sortField).order(sortRule.equals("DESC")? SortOrder.DESC:SortOrder.ASC));
        }
        // 设置高亮的条件
        nativeSearchQueryBuilder.withHighlightFields(new HighlightBuilder.Field("title"));
        nativeSearchQueryBuilder.withHighlightBuilder(new HighlightBuilder().preTags("<em style=\"color:red\">").postTags("</em>"));
        // 构建器构建查询对象
        NativeSearchQuery query = nativeSearchQueryBuilder.build();
        // 执行查询
        SearchHits<com.offcn.search.pojo.Item> searchHits = elasticsearchRestTemplate.search(query, com.offcn.search.pojo.Item.class);
        // 处理高亮结果
        for (SearchHit<com.offcn.search.pojo.Item> searchHit : searchHits) {
            // 获取高亮的内容
            Map<String, List<String>> highlightFields = searchHit.getHighlightFields();
            System.out.println(highlightFields);
            // 获取标题上的高亮结果
            searchHit.getContent().setTitle(highlightFields.get("title")==null?
                    searchHit.getContent().getTitle():highlightFields.get("title").get(0));
            System.out.println(searchHit.getContent().getTitle());
        }
        SearchPage<com.offcn.search.pojo.Item> searchPage = SearchHitSupport.searchPageFor(searchHits, query.getPageable());
        // 获取分组的结果
        Terms categoryTerms  = searchHits.getAggregations().get("CategoryGroup");
        List<String> categoryList = this.getCategoryTerms(categoryTerms);
        Terms brandTerms  = searchHits.getAggregations().get("BrandGroup");
        List<String> brandList = this.getBrandTerms(brandTerms);
        Terms specTerms  = searchHits.getAggregations().get("SpecGroup");
        Map<String , Set<String >> specMap = this.getSpecGroup(specTerms);

        List<com.offcn.search.pojo.Item> skuList = new ArrayList<>();
        for (SearchHit<com.offcn.search.pojo.Item> searchHit : searchPage) {
            com.offcn.search.pojo.Item content = searchHit.getContent();
            com.offcn.search.pojo.Item item = new com.offcn.search.pojo.Item();
            BeanUtils.copyProperties(content,item);
            skuList.add(item);
        }
        // 返回结果
        Map resultMap = new HashMap();
        resultMap.put("rows",skuList);
        resultMap.put("total",searchHits.getTotalHits());
        resultMap.put("totalPages",searchPage.getTotalPages());
        resultMap.put("categoryList",categoryList);
        resultMap.put("brandList",brandList);
        resultMap.put("specMap",specMap);
        resultMap.put("pageNum",pageNum);
        resultMap.put("pageSize",pageSize);
        return resultMap;
    }
    private Map<String, Set<String>> getSpecGroup(Terms specTerms) {
        Map<String ,Set<String>> specMap = new HashMap<>();
        Set<String > specList = new HashSet<>();
        if (specTerms != null){
            for (Terms.Bucket bucket : specTerms.getBuckets()) {
                specList.add(bucket.getKeyAsString());
            }
        }
        for (String json : specList) {
            Map<String ,String> map = JSON.parseObject(json, Map.class);
            for (Map.Entry<String, String> entry : map.entrySet()) {
                String key = entry.getKey();
                String value = entry.getValue();
                Set<String> strings = specMap.get(key);
                if (strings == null){
                    strings = new HashSet<>();
                }
                strings.add(value);
                specMap.put(key,strings);
            }
        }
        return specMap;
    }
    private List<String> getBrandTerms(Terms brandTerms) {
        List<String > brandList = new ArrayList<>();
        if (null != brandTerms){
            for (Terms.Bucket bucket : brandTerms.getBuckets()) {
                String key = bucket.getKeyAsString();
                brandList.add(key);
            }
        }
        return brandList;
    }
    private List<String > getCategoryTerms(Terms terms){
        List<String > categoryList = new ArrayList<>();
        if (null != terms){
            for (Terms.Bucket bucket : terms.getBuckets()) {
                String key = bucket.getKeyAsString();
                categoryList.add(key);
            }
        }
        return categoryList;
    }
}
